﻿
#region ConvertTo-KMSStatus 

function ConvertTo-KMSStatus
{
	[cmdletbinding()]
	Param(
		[Parameter(mandatory=$true)]
		[int]$StatusCode
	)
	switch -exact ($StatusCode)
	{
		0		{"Unlicensed"}
		1		{"Licensed"}
		2		{"OOBGrace"}
		3		{"OOTGrace"}
		4		{"NonGenuineGrace"}
		5		{"Notification"}
		6		{"ExtendedGrace"}
		default {"Unknown"}
	}
}
#endregion 


#region Get-KMSActivationDetail 

function Get-KMSActivationDetail
{

    <#
        .Synopsis 
            Gets the Activation Detail from the KMS Server.
            
        .Description
            Gets the Activation Detail from the KMS Server.
            
        .Parameter KMS
            KMS Server to connect to.
            
        .Parameter Filter
            Filter for the Computers to get activation for.
        
        .Parameter After
            The DateTime to start the query from. For example if I only want activations for the last thirty days:
            the date time would be ((Get-Date).AddMonths(-1))
            
        .Parameter Unique
            Only return Unique entries.
            
        .Example
            Get-KMSActivationDetail -kms MyKMSServer
            Description
            -----------
            Get all the activations for the target KMS server.
            
        .Example
            Get-KMSActivationDetail -kms MyKMSServer -filter mypc
            Description
            -----------
            Get all the activations for all the machines that are like "mypc" on the target KMS server.
            
        .Example
            Get-KMSActivationDetail -kms MyKMSServer -After ((Get-Date).AddDays(-1))
            Description
            -----------
            Get all the activations for the last day on the target KMS server.
    
        .Example
            Get-KMSActivationDetail -kms MyKMSServer -unique
            Description
            -----------
            Returns all the unique activate for the targeted KMS server.
            
        .OUTPUTS
            PSCustomObject
            
        .INPUTS
            System.String
            
        .Link
            Get-KMSServer
            Get-KMSStatus
            
        .Notes
            NAME:      Get-KMSActivationDetail
            AUTHOR:    bsonposh
            Website:   http://www.bsonposh.com
            Version:   1
            #Requires -Version 2.0
    #>
    
    [Cmdletbinding()]
    Param(
    
        [Parameter(mandatory=$true)]
        [string]$KMS,
        
        [Parameter()]
        [string]$Filter="*",
        
        [Parameter()]
        [datetime]$After,
        
        [Parameter()]
        [switch]$Unique
        
    )
    Write-Verbose " [Get-KMSActivationDetail] :: Cmdlet Start"
    Write-Verbose " [Get-KMSActivationDetail] :: KMS Server   = $KMS"
    Write-Verbose " [Get-KMSActivationDetail] :: Filter       = $Filter"
    Write-Verbose " [Get-KMSActivationDetail] :: After Date   = $After"
    Write-Verbose " [Get-KMSActivationDetail] :: Unique       = $Unique"
    
    if($After)
    {
        Write-Verbose " [Get-KMSActivationDetail] :: Processing Records after $After"
        $Events = Get-Eventlog -LogName "Key Management Service" -ComputerName $KMS -After $After -Message "*$Filter*"
    }
    else
    {
        Write-Verbose " [Get-KMSActivationDetail] :: Processing Records"
        $Events = Get-Eventlog -LogName "Key Management Service" -ComputerName $KMS -Message "*$Filter*"
    }
    
    Write-Verbose " [Get-KMSActivationDetail] :: Creating Objects Collection"
    $MyObjects = @()
    
    Write-Verbose " [Get-KMSActivationDetail] :: Processing {$($Events.count)} Events"
    foreach($Event in $Events)
    {
        Write-Verbose " [Get-KMSActivationDetail] :: Creating Hash Table [$($Event.Index)]"
        $Message = $Event.Message.Split(",")
        
        $myobj = @{}
        Write-Verbose " [Get-KMSActivationDetail] :: Setting ComputerName to $($Message[3])"
        $myobj.Computername = $Message[3]
        Write-Verbose " [Get-KMSActivationDetail] :: Setting Date to $($Event.TimeGenerated)"
        $myobj.Date = $Event.TimeGenerated
        Write-Verbose " [Get-KMSActivationDetail] :: Creating Custom Object [$($Event.Index)]"
        $MyObjects += New-Object PSObject -Property $myobj
    }
    
    if($Unique)
    {
        Write-Verbose " [Get-KMSActivationDetail] :: Parsing out Unique Objects"
        $UniqueObjects = $MyObjects | Group-Object -Property Computername
        foreach($UniqueObject in $UniqueObjects)
        {
            $myobj = @{}
            $myobj.ComputerName = $UniqueObject.Name
            $myobj.Count = $UniqueObject.count
    
            $obj = New-Object PSObject -Property $myobj
            $obj.PSTypeNames.Clear()
            $obj.PSTypeNames.Add('BSonPosh.KMS.ActivationDetail')
            $obj
        }
        
    }
    else
    {
        $MyObjects
    }

}
#endregion 


#region Get-KMSServer 

function Get-KMSServer
{
    
    <#
        .Synopsis 
            Gets the KMS Server.
            
        .Description
            Gets a PSCustomObject (BSonPosh.KMS.Server) for the KMS Server.
            
        .Parameter KMS
            KMS Server to get.
            
        .Example
            Get-KMSServer -kms MyKMSServer
            Description
            -----------
            Gets a KMS Server object for 'MyKMSServer'
    
        .OUTPUTS
            PSCustomObject
            
        .INPUTS
            System.String
            
        .Link
            Get-KMSActivationDetail
            Get-KMSStatus
            
        .Notes
            NAME:      Get-KMSServer
            AUTHOR:    bsonposh
            Website:   http://www.bsonposh.com
            Version:   1
            #Requires -Version 2.0
    #>
    
    [Cmdletbinding()]
    Param(
        [Parameter(ValueFromPipelineByPropertyName=$true,ValueFromPipeline=$true)]
        [string]$KMS
    )
    if(!$KMS)
    {
        Write-Verbose " [Get-KMSServer] :: No KMS Server Passed... Using Discovery"
        $KMS = Test-KMSServerDiscovery | select -ExpandProperty ComputerName
    }
    try
    {
        Write-Verbose " [Get-KMSServer] :: Querying KMS Service using WMI"
        $KMSService = Get-WmiObject "SoftwareLicensingService" -ComputerName $KMS
        $myobj = @{
            ComputerName            = $KMS
            Version                 = $KMSService.Version
            KMSEnable               = $KMSService.KeyManagementServiceActivationDisabled -eq $false
            CurrentCount            = $KMSService.KeyManagementServiceCurrentCount
            Port                    = $KMSService.KeyManagementServicePort
            DNSPublishing           = $KMSService.KeyManagementServiceDnsPublishing
            TotalRequest            = $KMSService.KeyManagementServiceTotalRequests
            FailedRequest           = $KMSService.KeyManagementServiceFailedRequests
            Unlicensed              = $KMSService.KeyManagementServiceUnlicensedRequests
            Licensed                = $KMSService.KeyManagementServiceLicensedRequests
            InitialGracePeriod      = $KMSService.KeyManagementServiceOOBGraceRequests
            LicenseExpired          = $KMSService.KeyManagementServiceOOTGraceRequests
            NonGenuineGracePeriod   = $KMSService.KeyManagementServiceNonGenuineGraceRequests
            LicenseWithNotification = $KMSService.KeyManagementServiceNotificationRequests
            ActivationInterval      = $KMSService.VLActivationInterval
            RenewalInterval         = $KMSService.VLRenewalInterval
        }
    
        $obj = New-Object PSObject -Property $myobj
        $obj.PSTypeNames.Clear()
        $obj.PSTypeNames.Add('BSonPosh.KMS.Server')
        $obj
    }
    catch
    {
        Write-Verbose " [Get-KMSServer] :: Error: $($Error[0])"
    }

}
#endregion 


#region Get-KMSStatus 

function Get-KMSStatus
{

    <#
        .Synopsis 
            Gets the KMS status from the Computer Name specified.
            
        .Description
            Gets the KMS status from the Computer Name specified (Default local host.) Returns a custom object (BSonPosh.KMS.Status)
            
        .Parameter ComputerName
            Computer to get the KMS Status for.
        
        .Example
            Get-KMSStatus mypc
            Description
            -----------
            Returns a KMS status object for Computer 'mypc'
    
        .OUTPUTS
            PSCustomObject
            
        .INPUTS
            System.String
            
        .Link
            Get-KMSActivationDetail
            Get-KMSServer
            
        .Notes
            NAME:      Get-KMSStatus
            AUTHOR:    bsonposh
            Website:   http://www.bsonposh.com
            Version:   1
            #Requires -Version 2.0
    #>
    
    [Cmdletbinding()]
    Param(
        [Parameter(ValueFromPipelineByPropertyName=$true,ValueFromPipeline=$true)]
        [string]$ComputerName = $Env:COMPUTERNAME
    )
    Process 
    {
    
        Write-Verbose " [Get-KMSStatus] :: Process Start"
        if($ComputerName -match "(.*)(\$)$")
        {
            $ComputerName = $ComputerName -replace "(.*)(\$)$",'$1'
        }
        $Query = "Select * FROM SoftwareLicensingProduct WHERE Description LIKE '%VOLUME_KMSCLIENT%'"
        Write-Verbose " [Get-KMSStatus] :: ComputerName = $ComputerName"
        Write-Verbose " [Get-KMSStatus] :: Query = $Query"
        try
        {
            Write-Verbose " [Get-KMSStatus] :: Calling WMI"
            $WMIResult = Get-WmiObject -ComputerName $ComputerName -query $Query
            foreach($result in $WMIResult)
            {
                Write-Verbose " [Get-KMSStatus] :: Creating Hash Table"
                $myobj = @{}
                Write-Verbose " [Get-KMSStatus] :: Setting ComputerName to $ComputerName"
                $myobj.ComputerName = $ComputerName
                Write-Verbose " [Get-KMSStatus] :: Setting KMSServer to $($result.KeyManagementServiceMachine)"
                $myobj.KMSServer = $result.KeyManagementServiceMachine
                Write-Verbose " [Get-KMSStatus] :: Setting KMSPort to $($result.KeyManagementServicePort)"
                $myobj.KMSPort = $result.KeyManagementServicePort
                Write-Verbose " [Get-KMSStatus] :: Setting LicenseFamily to $($result.LicenseFamily)"
                $myobj.LicenseFamily = $result.LicenseFamily
                Write-Verbose " [Get-KMSStatus] :: Setting Status to $($result.LicenseStatus)"
                $myobj.Status = ConvertTo-KMSStatus $result.LicenseStatus
                Write-Verbose " [Get-KMSStatus] :: Creating Object"
    
                $obj = New-Object PSObject -Property $myobj
                $obj.PSTypeNames.Clear()
                $obj.PSTypeNames.Add('BSonPosh.KMS.Status')
                $obj
            }
        }
        catch
        {
            Write-Verbose " [Get-KMSStatus] :: Error - $($Error[0])"
        }
    
    }

}
#endregion 


#region Test-KMSIsActivated 

function Test-KMSIsActivated 
{
        
    <#
        .Synopsis 
            Test machine for activation.
            
        .Description
            Test machine for activation.
            
        .Parameter ComputerName
            Name of the Computer to test activation on (Default is localhost.)
            
        .Example
            Test-KMSIsActivated
            Description
            -----------
            Test activation on local machine
    
        .Example
            Test-KMSIsActivated -ComputerName MyServer
            Description
            -----------
            Test activation on MyServer
            
        .Example
            $Servers | Test-KMSIsActivated
            Description
            -----------
            Test activation for each machine in the pipeline
            
        .OUTPUTS
            Object
            
        .INPUTS
            System.String
            
        .Link
            N/A
            
        .Notes
            NAME:      Test-KMSIsActivated
            AUTHOR:    bsonposh
            Website:   http://www.bsonposh.com
            Version:   1
            #Requires -Version 2.0
    #>
    
    [Cmdletbinding()]
    Param(
    
        [alias('dnsHostName')]
        [Parameter(ValueFromPipelineByPropertyName=$true,ValueFromPipeline=$true)]
        [string]$ComputerName = $Env:COMPUTERNAME
        
    )
    
    Process 
    {
    
        Write-Verbose " [Test-KMSActivation] :: Process start"
        if($ComputerName -match "(.*)(\$)$")
        {
            $ComputerName = $ComputerName -replace "(.*)(\$)$",'$1'
        }
        Write-Verbose " [Test-KMSActivation] :: ComputerName = $ComputerName"
        if(Test-Host $ComputerName -TCP 135)
        {
            Write-Verbose " [Test-KMSActivation] :: Process start"
            $status = Get-KMSStatus -ComputerName $ComputerName
            if($status.Status -eq "Licensed")
            {
                $_
            }
        }
    
    }
}
    
#endregion 


#region Test-KMSServerDiscovery 

function Test-KMSServerDiscovery
{
    
    <#
        .Synopsis 
            Test KMS server discovery.
            
        .Description
            Test KMS server discovery.
            
        .Parameter DNSSuffix
            DNSSuffix to do discovery on.
            
        .Example
            Test-KMSServerDiscovery
            Description
            -----------
            Test KMS server discovery on local machine
            
        .OUTPUTS
            PSCustomObject (BSonPosh.KMS.DiscoveryResult)
            
        .INPUTS
            System.String
            
        .Link
            N/A
            
        .Notes
            NAME:      Test-KMSServerDiscovery
            AUTHOR:    bsonposh
            Website:   http://www.bsonposh.com
            Version:   1
            #Requires -Version 2.0
    #>
    
    [Cmdletbinding()]
    Param($DNSSuffix)
    
    Write-Verbose " [Test-KMSServerDiscovery] :: cmdlet started"
    Write-Verbose " [Test-KMSServerDiscovery] :: Getting dns primary suffix from registry"
    if(!$DNSSuffix)
    {
        $key = get-item -path HKLM:\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters
        $DNSSuffix = $key.GetValue("Domain")
    }
    Write-Verbose " [Test-KMSServerDiscovery] :: DNS Suffix = $DNSSuffix"
    $record = "_vlmcs._tcp.${DNSSuffix}"
    Write-Verbose " [Test-KMSServerDiscovery] :: SRV Record to query for = $record"
    $NameRegEx = "\s+svr hostname   = (?<HostName>.*)$"
    $PortRegEX = "\s+(port)\s+ = (?<Port>\d+)"
    try
    {
        Write-Verbose " [Test-KMSServerDiscovery] :: Running nslookup"    
        Write-Verbose " [Test-KMSServerDiscovery] :: Command - nslookup -type=srv $record 2>1 | select-string `"svr hostname`" -Context 4,0"
        $results = nslookup -type=srv $record 2>1 | select-string "svr hostname" -Context 4,0
        if($results)
        {
            Write-Verbose " [Test-KMSServerDiscovery] :: Found Entry: $Results"
        }
        else
        {
            Write-Verbose " [Test-KMSServerDiscovery] :: No Results found"
            return
        }
        Write-Verbose " [Test-KMSServerDiscovery] :: Creating Hash Table"    
        $myobj = @{}
        switch -regex ($results -split "\n")
        {
            $NameRegEx  {
                            Write-Verbose " [Test-KMSServerDiscovery] :: ComputerName = $($Matches.HostName)"    
                            $myobj.ComputerName = $Matches.HostName
                        }
            $PortRegEX  {
                            Write-Verbose " [Test-KMSServerDiscovery] :: IP = $($Matches.Port)"
                            $myobj.Port = $Matches.Port
                        }
            Default     {
                            Write-Verbose " [Test-KMSServerDiscovery] :: Processing line: $_"
                        }
        }
        Write-Verbose " [Test-KMSServerDiscovery] :: Creating Object"
        $obj = New-Object PSObject -Property $myobj
        $obj.PSTypeNames.Clear()
        $obj.PSTypeNames.Add('BSonPosh.KMS.DiscoveryResult')
        $obj
    }
    catch
    {
        Write-Verbose " [Test-KMSServerDiscovery] :: Error: $($Error[0])"
    }

}
#endregion 


#region Test-KMSSupport 

function Test-KMSSupport 
{
        
    <#
        .Synopsis 
            Test machine for KMS Support.
            
        .Description
            Test machine for KMS Support.
            
        .Parameter ComputerName
            Name of the Computer to test KMS Support on (Default is localhost.)
            
        .Example
            Test-KMSSupport
            Description
            -----------
            Test KMS Support on local machine
    
        .Example
            Test-KMSSupport -ComputerName MyServer
            Description
            -----------
            Test KMS Support on MyServer
            
        .Example
            $Servers | Test-KMSSupport
            Description
            -----------
            Test KMS Support for each machine in the pipeline
            
        .OUTPUTS
            Object
            
        .INPUTS
            System.String
            
        .Link
            N/A
            
        .Notes
            NAME:      Test-KMSSupport
            AUTHOR:    bsonposh
            Website:   http://www.bsonposh.com
            Version:   1
            #Requires -Version 2.0
    #>
    
    [Cmdletbinding()]
    Param(
    
        [alias('dnsHostName')]
        [Parameter(ValueFromPipelineByPropertyName=$true,ValueFromPipeline=$true)]
        [string]$ComputerName = $Env:COMPUTERNAME
        
    )
    
    Process 
    {
        Write-Verbose " [Test-KMSSupport] :: Process start"
        if($ComputerName -match "(.*)(\$)$")
        {
            $ComputerName = $ComputerName -replace "(.*)(\$)$",'$1'
        }
        Write-Verbose " [Test-KMSSupport] :: Testing Connectivity"
        if(Test-Host -ComputerName $ComputerName -TCPPort 135)
        {
            $Query = "Select __CLASS FROM SoftwareLicensingProduct"
            try
            {
                Write-Verbose " [Test-KMSSupport] :: Running WMI Query"
                $Result = Get-WmiObject -Query $Query -ComputerName $ComputerName
                Write-Verbose " [Test-KMSSupport] :: Result = $($Result.__CLASS)"
                if($Result)
                {
                    Write-Verbose " [Test-KMSSupport] :: Return $_"
                    $_
                }
            }
            catch
            {
                Write-Verbose " [Test-KMSSupport] :: Error: $($Error[0])"
            }
        }
        else
        {
            Write-Verbose " [Test-KMSSupport] :: Failed Connectivity Test"
        }
    
    }
}
    
#endregion 

